#ifndef COSTFLOWEDGEATTRIBUTES_H_
#define COSTFLOWEDGEATTRIBUTES_H_

#include "graph_support/attributes/FlowEdgeAttributes.h"


namespace GRAPH_SUPPORT_NS
{
namespace attributes
{

class CostFlowEdgeAttributes : public FlowEdgeAttributes
{
public:
	class Cost
	{
	// 4:		cap = 0;
	public:
		Cost( int );
		const Cost & operator = ( const int & );

	// compare
	public:
		bool operator < ( const Cost & ) const;
		bool operator <= ( const Cost & ) const;
		bool operator > ( const Cost & ) const;
		bool operator >= ( const Cost & ) const;
		bool operator == ( const Cost & ) const;

	// arithmetic
	public:
		const Cost & operator + ( const Cost & ) const;
		const Cost & operator - ( const Cost & ) const;
		const Cost & operator += ( const Cost & ) const;
		const Cost & operator -= ( const Cost & ) const;
	public:
		const Cost & operator * ( const Capacity & ) const;

	protected:
		Cost() {} // default constructor is available
	};

public:
	Cost getCost() const;
	void setCost( const Cost & cost );
	static Cost getINFCost();
};

template< typename CapacityT, typename CostT = CapacityT, long INF = 1 << 30 >
class CostFlowEdgeAttributesTmpl : public CostFlowEdgeAttributes, public FlowEdgeAttributesTmpl< CapacityT >
{
public:
	typedef CapacityT Capacity;
	typedef CostT Cost;
private:
	// TODO: SuperT name convention
	typedef FlowEdgeAttributesTmpl< Capacity > FlowSuper;
	typedef CostFlowEdgeAttributesTmpl< Capacity, Cost > MyT;

public:
	CostFlowEdgeAttributesTmpl( const Capacity & capacity, const Cost & cost )
		: FlowSuper( capacity )
		, cost( cost )
	{
	}

	CostFlowEdgeAttributesTmpl( int )
		: FlowSuper( 0 )
		, cost( 0 )
	{
	}

	CostFlowEdgeAttributesTmpl()
		: cost( 0 )
	{
	}

public:
	Cost getCost() const
	{
		assert( ! FlowSuper::staticBidirectedRequired || FlowSuper::revertedEdgeAttributes != NULL );
		return cost;
	}

	void setCost( const Cost & cost )
	{
		this->cost = cost;
		MyT * revertedEdgeAttributes = ( MyT * ) FlowSuper::revertedEdgeAttributes;
		revertedEdgeAttributes->cost = -cost;
	}

	static Cost getINFCost()
	{
		return INF;
	}

	void onBidirEdgeCreated( MyT & revertedAttributes, bool isOriginalEdge = true )
	{
		FlowSuper::revertedEdgeAttributes = & revertedAttributes;
		if ( ! isOriginalEdge )
		{
			FlowSuper::capacity = 0;
			cost = -revertedAttributes.cost;
		}
	}

private:
	Cost cost;
};

}
}

#endif /* COSTFLOWEDGEATTRIBUTES_H_ */
